'''
CashTrade 现货交易封装
'''

import logging
from src.serve.api import API
from src.serve.public import Public
from src.serve.macd import MACD
from src.model.asset_balance import AssetBalanceModel
from src.util import util
from src.chatbot import Chatbot
from src.model.cash_trade import CashTradeModel
from src.model.config import ConfigModel
# Client同步客户端, AsyncClient为异步客户端
from binance.client import Client


class CashTrade:
    ''' 现货交易
        只支持做多交易，即只有购买的币后卖出，不能做空做多交易
    '''
    def __init__(self, options):
        self.retry = 10  # 重试次数
        self.sleepTime = 60  # 等待时间30秒
        self.limitDiffPrice = 5  # 限制价差

        self.config = ConfigModel(options)
        self.tradeOrderData = None  # 存储订单数据

        self.asset = self.config.asset  # 默认使用兑换币种

        # 日志
        logging.basicConfig(level=logging.INFO)
        self.logger = logging.getLogger()

        # 客户端 可通过config获取对应程序apiKey和secretKey
        self.client = Client(self.config.apiKey,
                             self.config.secretKey,
                             testnet=self.config.testnet)

        # 钉钉客户端
        dingdingConf = self.config.dingding
        dingdingConf.setLogger(self.logger)
        self.chatbot = Chatbot(dingdingConf)

        # 初始化相关工具
        self._initUtil()

        # 初始化tradeOrderData数据
        self.initTradeOrder()

    def _initUtil(self):
        self.api = API({
            'client': self.client,
            'logger': self.logger,
            'chatbot': self.chatbot
        })
        self.public = Public({'logger': self.logger, 'chatbot': self.chatbot})
        self.macd = MACD({'logger': self.logger, 'chatbot': self.chatbot})

    def exchange(self, symbol, quantity=0.00500, interval=None):
        # 获得交易方向
        side = self.exchangeSide(symbol, interval)

        # 订单数据
        tradeOrderData = self.tradeOrderData
        # 是否为初始订单数据，判断标准为orderId，和origQty是否存
        isInitOrderData = tradeOrderData.orderId is None or tradeOrderData.origQty is None
        if (isInitOrderData):
            tradeOrderData = self.getLatestTrade(symbol=symbol)
            # 存储订单数据
            self.saveCashTradeData(tradeOrderData)

        # 只有出现 buy|sell才执行
        if side == 'BUY' or side == 'SELL' and isInitOrderData is False:

            # 获取到市场此时报价
            price = self.api.getPrice(symbol)

            # 检测报价是否正常
            exchangeInfo = self.api.exchangeInfo()
            isQuoteOK = self.public.priceFilter(exchangeInfo, symbol, price)

            # 超出了现价不做下单
            if self.isLimitDiffPrice(symbol, side,
                                     price) and isQuoteOK is False:
                return

            # 发出买入还是卖出信号进行下单处理
            assetBalance = self.api.getAssetBalance(self.asset)
            isEnough = self.public.isEnoughAsset(assetBalance, quantity, price)
            if side == 'BUY' and isEnough:
                self.chatbot.sendmsg('side:{},quantity:{},price:{}'.format(
                    side, quantity, price))
                tradeOrderData = self.api.orderLimit(symbol,
                                                     side,
                                                     quantity=quantity,
                                                     price=price)
                # 存储订单数据
                self.saveCashTradeData(tradeOrderData)

            elif side == 'SELL' and tradeOrderData.side != 'SELL':
                # 卖出时需要获取最新的可用资产(assetBalance.free), 这时的资产可能小于购买时的quantity；
                asset = symbol.split(self.asset)[0]
                assetBalance = self.api.getAssetBalance(asset)
                quantity = round(
                    assetBalance.free -
                    self.public.countTip(assetBalance.free), 5)
                self.chatbot.sendmsg(
                    'side:{},free:{},quantity:{},price:{}'.format(
                        side, assetBalance.free, quantity, price))
                tradeOrderData = self.api.orderLimit(symbol,
                                                     side,
                                                     quantity=quantity,
                                                     price=price)

                # 存储订单数据
                self.saveCashTradeData(tradeOrderData)

    def exchangeSide(self, symbol, interval):
        ''' 交易方向
        通过K线进行指标分析获得买卖持有标识

        retrun side BUY|SELL|HOLD 买，卖，持有
        '''
        data = self.api.getKLines(symbol, interval)
        # 获得购买方向
        side = self.macd.getStatus(data)
        return side

    def initTradeOrder(self):
        self.tradeOrderData = CashTradeModel({})
        self.saveCashTradeData(self.tradeOrderData)

    def isLimitDiffPrice(self, symbol, side, price):
        # 用于判断行情是否属于最高 防止追高
        tickers = self.api.getTicker(symbol=symbol)
        highPrice = float(tickers.get('highPrice', 0))
        # side 不受限价差控制，需要继续卖出
        if side == 'BUY':
            status = highPrice - price > self.limitDiffPrice
        else:
            status = False
        message = '最高价格判断 curretPrice:{highPrice},side:{side},price:{price},status:{status}'.format(
            highPrice=highPrice, side=side, price=price, status=status)
        self.logger.info(message)
        return status

    def getLatestTrade(self, symbol, orderId=None):
        if orderId is None:
            res = self.api.getMyTrades(symbol=symbol)
        else:
            res = self.api.getOrder(symbol, orderId)
        tradeOrderData = CashTradeModel(res)
        self.public.checkOrder(tradeOrderData)
        return tradeOrderData

    def saveCashTradeData(self, tradeOrderData):
        ''' 交易数据存储
        :params tradeOrderData 交易数据 CashTradeModel|None
        '''
        if tradeOrderData is None: return

        if tradeOrderData.side == 'SELL' and tradeOrderData.status is not None:
            # 出现卖出信号时，进行利润统计
            saveTradeOrderData = self.tradeOrderData
            self.public.countProfit(saveTradeOrderData, tradeOrderData)

        self.tradeOrderData = tradeOrderData
        dictData = tradeOrderData.__dict__
        fillsData = tradeOrderData.fills
        if fillsData is not None:
            dictData.fills = fillsData.__dict__
        # 写本地数据，做记录，并返回数据
        # strtime = time.strftime('%y-%m-%d', time.localtime())
        util.write('./data/cash_order.json', dictData)
